<?php

abstract class ValidationRule
{
  protected $message;

  public function __construct($message)
  {
    $this->message = $message;
  }

  public function getMessage()
  {
    return $this->message;
  }

  abstract public function validate($value);
}

/**
 * NumericValidationRule
 *
 * @package 
 * @author Michael Thomas
 * @copyright 2008
 * @version $Id$
 * @access public
 */
class NumericValidationRule extends ValidationRule
{

  /**
   * NumericValidationRule::__construct()
   *
   * @param string $message
   * @return void
   */
  public function __construct($message = 'This must be a number')
  {
    $this->message = $message;
  }

  /**
   * NumericValidationRule::validate()
   *
   * @param mixed $value
   * @return
   */
  public function validate($value)
  {
    return is_numeric($value) || $value == '';
  }
}

/**
 * RegexValidationRule
 *
 * Validates using a regular expression.  
 *
 * @package 
 * @author Michael Thomas
 * @copyright 2008
 * @version $Id$
 * @access public
 */
class RegexValidationRule extends ValidationRule
{
  protected $regularExpression;

  /**
   * RegexValidationRule::__construct()
   *
   * @param mixed $regularExpression
   * @return void
   */
  public function __construct($regularExpression, $message)
  {
    $this->regularExpression = $regularExpression;
    $this->message = $message;
  }

  /**
   * RegexValidationRule::validate()
   *
   * @param mixed $value
   * @return
   */
  public function validate($value)
  {
    return preg_match($this->regularExpression, $value);
  }
}

/**
 * ExistsValidationRule
 *
 * Given a mysql table and column, this validation rule returns true if the
 * supplied value is present.
 *
 * @package 
 * @author Michael Thomas
 * @copyright 2008
 * @version $Id$
 * @access public
 */
class ExistsValidationRule extends ValidationRule
{
  protected $mysqlTable;
  protected $mysqlColumn;
  protected $mysqlDatabase;

  /**
   * UniqueValidationRule::__construct()
   *
   * @param mixed $mysqlTable
   * @param mixed $mysqlColumn
   * @param mixed $mysqlDatabase
   * @return void
   */
  public function __construct($mysqlTable, $mysqlColumn, $mysqlDatabase = null,
      $message)
  {
    $this->mysqlTable = $mysqlTable;
    $this->mysqlColumn = $mysqlColumn;
    $this->mysqlDatabase = $mysqlDatabase;
    $this->message = $message;
  }

  /**
   * UniqueValidationRule::validate()
   *
   * @param mixed $value
   * @return boolean
   */
  public function validate($value)
  {
    $from = (!is_null($this->mysqlDatabase)) ?
        "$this->mysqlDatabase.$this->mysqlTable" : $this->mysqlTable;
    $query = "SELECT $this->mysqlColumn
              FROM $from
              WHERE $this->mysqlColumn = '$value'
              LIMIT 1";
    $result = Util::query($query);
    return mysql_num_rows($result) == 1;
  }
}

/**
 * UniqueValidationRule
 *
 * Given a mysql table and column, this validation rule returns true if the
 * supplied value is not present.
 *
 * @package 
 * @author Michael Thomas
 * @copyright 2008
 * @version $Id$
 * @access public
 */
class UniqueValidationRule extends ValidationRule
{
  protected $mysqlTable;
  protected $mysqlColumn;
  protected $mysqlDatabase;
  protected $mysqlConstraints = array();

  /**
   * UniqueValidationRule::__construct()
   *
   * @param mixed $mysqlTable
   * @param mixed $mysqlColumn
   * @param mixed $mysqlDatabase
   * @return void
   */
  public function __construct($mysqlTable, $mysqlColumn, $mysqlDatabase = null,
      $message = 'Record already exists')
  {
    $this->mysqlTable = $mysqlTable;
    $this->mysqlColumn = $mysqlColumn;
    $this->mysqlDatabase = $mysqlDatabase;
    $this->message = $message;
  }

  public function addConstraint($constraint)
  {
    $this->mysqlConstraints[] = $constraint;
  }

  /**
   * UniqueValidationRule::validate()
   *
   * @param mixed $value
   * @return boolean
   */
  public function validate($value)
  {
    $from = ($this->mysqlDatabase) ? "$this->mysqlDatabase.$this->mysqlTable" :
        $this->mysqlTable;
    $query = "SELECT $this->mysqlColumn
              FROM $from
              WHERE $this->mysqlColumn = '$value'";
    foreach ($this->mysqlConstraints as $constraint) {
      $query .= " AND $constraint";
    }
    $query .= " LIMIT 1";
    $result = Util::query($query);
    return mysql_num_rows($result) == 0;
  }
}


/**
 * SetUniqueValidationRule
 *
 * An extension of UniqueValidatonRule which works with sets (i.e. comma
 * separated values in a mysql column)
 *
 * @package 
 * @author Michael Thomas
 * @copyright 2008
 * @version $Id$
 * @access public
 */

class SetUniqueValidationRule extends UniqueValidationRule
{
  /**
   * UniqueValidationRule::validate()
   *
   * @param mixed $value
   * @return boolean
   */
  public function validate($value)
  {
    $from = ($this->mysqlDatabase) ? "$this->mysqlDatabase.$this->mysqlTable" :
        $this->mysqlTable;
    $query = "SELECT $this->mysqlColumn
              FROM $from
              WHERE FIND_IN_SET('$value',$this->mysqlColumn)";
    foreach ($this->mysqlConstraints as $constraint) {
      $query .= " AND $constraint";
    }
    $query .= " LIMIT 1";
    $result = Util::query($query);
    return mysql_num_rows($result) == 0;
  }
}

?>